home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / unzip42.zip / MAPNAME.C < prev    next >
C/C++ Source or Header  |  1992-03-15  |  14KB  |  333 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   mapname.c
  4.  
  5.   This routine changes DEC-20, VAX/VMS, and DOS-style filenames into normal
  6.   Unix names (and vice versa, in some cases); it also creates any necessary 
  7.   directories, if the -d switch was specified.
  8.  
  9.   ---------------------------------------------------------------------------
  10.  
  11.   Notes:
  12.  
  13.      - Unix allows multiple dots in directory names; MS-DOS and OS/2 FAT
  14.        allow one; VMS does not allow any.  Things are almost as bad with
  15.        regular filenames (VMS allows a single dot but TOPS-20 allows two,
  16.        if you count the one in front of the version number).  As of v4.04,
  17.        mapname converts directory-name dots to underscores on VMS, but it
  18.        otherwise leaves the dots alone.  Since it is now possible to create
  19.        zipfiles under Unix, this whole routine pretty much needs to be
  20.        rewritten (different routines for each output OS, and different 
  21.        rules for different parts of the path name).
  22.      - If each zip program stores local-format names (like the VMS one did
  23.        at one time), it would probably be best to convert to an intermedi-
  24.        ate format first (assuming we're not extracting under the same OS 
  25.        as that under which the zipfile was created), then from that to the 
  26.        current operating system's format.
  27.      - The strcpy and strcat operations on both cdp and filename may over-
  28.        write memory, since they don't check lengths.  With a kilobyte in
  29.        which to work, this is probably not that big a deal, but it could
  30.        cause problems eventually.
  31.  
  32.   ------------------------------------------------------------------------- */
  33.  
  34.  
  35. #include "unzip.h"
  36.  
  37.  
  38. /*******************/
  39. /* Mapname Defines */
  40. /*******************/
  41.  
  42. #ifdef VMS
  43. #  define PERMS   0
  44. #else
  45. #  define PERMS   0777
  46. #endif
  47.  
  48. #ifndef NO_MKDIR
  49. #  ifdef DOS_OS2
  50. #    if (_MSC_VER >= 600)       /* have special MSC mkdir prototype */
  51. #      include <direct.h>
  52. #    else                       /* own prototype because dir.h conflicts? */
  53.        int mkdir(const char *path);
  54. #    endif /* ?(MSC 6.0 or later) */
  55. #    define MKDIR(path,mode)   mkdir(path)
  56. #  else /* !DOS_OS2 */
  57. #    ifdef MACOS
  58. #      define MKDIR(path,mode)   mkdir(path)
  59. #    else /* !MACOS */
  60. #      define MKDIR(path,mode)   mkdir(path,mode)
  61. #    endif /* ?MACOS */
  62. #  endif /* ?DOS_OS2 */
  63. #endif /* !NO_MKDIR */
  64.  
  65.  
  66.  
  67.  
  68. /************************/
  69. /*  Function mapname()  */
  70. /************************/
  71.  
  72. int mapname(create_dirs)   /* return 0 if no error, 1 if caution (filename */
  73.     int create_dirs;       /*  truncated), 2 if warning (skip file because */
  74. {                          /*  dir doesn't exist), 3 if error (skip file) */
  75. #ifdef NO_MKDIR
  76.     char command[FILNAMSIZ+40]; /* buffer for system() call */
  77. #endif
  78. #ifdef VMS
  79.     int stat_val;               /* temp. holder for stat() return value */
  80.     char *dp, *xp;              /* pointers to directory name */
  81. #endif
  82. #ifdef OS2
  83.     char *last;
  84.     extern int longname;        /* used also in file_io.c:  set EAs */
  85.     extern char longfilename[]; /*  AFTER file created and closed */
  86. #endif
  87.     char name[FILNAMSIZ];       /* file name buffer */
  88.     char *pp, *cp, *cdp;        /* character pointers */
  89.     char delim = '\0';          /* directory delimiter */
  90.     int dc = 0;                 /* counters */
  91.     int quote = FALSE;          /* flags */
  92.     int indir = FALSE;
  93.     int done = FALSE;
  94.     register int workch;        /* hold the character being tested */
  95.  
  96.  
  97. /*---------------------------------------------------------------------------
  98.     Initialize various pointers and counters and stuff.
  99.   ---------------------------------------------------------------------------*/
  100.  
  101. #ifdef MAP_DEBUG
  102.     fprintf(stderr, "%s ", filename);   /* echo name of this file */
  103. #endif
  104.     pp = name;                  /* Point to translation buffer */
  105.     *name = '\0';               /* Initialize buffer */
  106.  
  107.     if (!jflag) {               /* -j => junk pathnames */
  108.         cdp = (char *) malloc(strlen(filename) + 3);  /* place for holding */
  109.         if (cdp == NULL) {                            /*  directory name */
  110.             fprintf(stderr, "mapname:  out of memory [%s]\n", filename);
  111.             return 3;
  112.         }
  113. #ifdef VMS
  114.         *cdp++ = '[';
  115.         xp = cdp;               /* always points to last non-NULL char */
  116.         *cdp++ = '.';
  117. #endif /* VMS */
  118. #ifdef MACOS
  119.         *cdp = ':';             /* the Mac uses ':' as a directory separator */
  120.         cdp[1] = '\0';
  121. #else /* !MACOS */
  122.         *cdp = '\0';
  123. #endif /* ?MACOS */
  124.     }
  125.     dc = 0;                     /* Filename dot counter */
  126.  
  127. /*---------------------------------------------------------------------------
  128.     Begin main loop through characters in filename.
  129.   ---------------------------------------------------------------------------*/
  130.  
  131.     for (cp = filename; (workch = *cp++) != 0  &&  !done;) {
  132.  
  133.         if (quote) {            /* If this char quoted... */
  134.             *pp++ = workch;     /*  include it literally. */
  135.             quote = FALSE;
  136.         } else if (indir) {     /* If in directory name... */
  137.             if (workch == delim)
  138.                 indir = FALSE;  /*  look for end delimiter. */
  139.         } else
  140.             switch (workch) {
  141.             case '<':           /* Discard DEC-20 directory name */
  142.                 indir = TRUE;
  143.                 delim = '>';
  144.                 break;
  145.             case '[':           /* Discard VMS directory name */
  146.                 indir = TRUE;
  147.                 delim = ']';
  148.                 break;
  149.             case '/':           /* Discard Unix path name... */
  150.             case '\\':          /*  or MS-DOS path name...
  151.                                  *  IF -j flag was given. */
  152.                 /*
  153.                  * Special processing case:  if -j flag was not specified on
  154.                  * command line and create_dirs is TRUE, create any necessary
  155.                  * directories included in the pathname.  Creation of dirs is
  156.                  * straightforward on BSD and MS-DOS machines but requires use
  157.                  * of the system() command on SysV systems (or any others which
  158.                  * don't have mkdir()).  The stat() check is necessary with
  159.                  * MSC because it doesn't have an EEXIST errno, and it saves
  160.                  * the overhead of multiple system() calls on SysV machines.
  161.                  */
  162.  
  163.                 if (!jflag) {
  164.                     *pp = '\0';
  165. #ifdef VMS
  166.                     dp = name;
  167.                     while (*++xp = *dp++)   /* copy name to cdp, while */
  168.                         if (*xp == '.')     /*   changing all dots... */
  169.                             *xp = '_';      /*   ...to underscores */
  170.                     strcpy(xp, ".dir");    /* add extension for stat check */
  171.                     stat_val = stat(cdp, &statbuf);
  172.                     *xp = '\0';         /* remove extension for all else */
  173.                     if (stat_val) {     /* doesn't exist, so create */
  174. #else /* !VMS */
  175.                     strcat(cdp, name);
  176. #ifdef OS2
  177.                     if (longname = !IsFileNameValid(cdp)) {
  178.                         last = strrchr(cdp, '/');
  179.                         strcpy(longfilename, last ? last + 1 : cdp);
  180.                         fprintf(stderr, "caution:  renaming directory \"%s\"",
  181.                           cdp);
  182.                         ChangeNameForFAT(cdp);
  183.                         fprintf(stderr, " to \"%s\"\n", cdp);
  184.                     }
  185. #endif /* OS2 */
  186.                     if (stat(cdp, &statbuf)) {  /* doesn't exist, so create */
  187. #endif /* ?VMS */
  188.                         if (!create_dirs) /* told not to create (freshening) */
  189.                             return 2;
  190. #ifdef NO_MKDIR
  191.                         sprintf(command,
  192.                           "IFS=\" \t\n\" /bin/mkdir %s 2>/dev/null", cdp);
  193.                         if (system(command)) {
  194. #else /* !NO_MKDIR */
  195.                         if (MKDIR(cdp, PERMS) == -1) {
  196. #endif /* ?NO_MKDIR */
  197.                             perror(cdp);
  198.                             free(cdp);
  199.                             fprintf(stderr, "mapame:  unable to process [%s]\n",
  200.                               filename);
  201.                             return 3;
  202.                         }
  203. #ifdef OS2
  204.                         if (longname)
  205.                             SetLongNameEA(cdp, longfilename);
  206. #endif /* OS2 */
  207.                     } else if (!(statbuf.st_mode & S_IFDIR)) {
  208.                         fprintf(stderr,
  209.                           "mapname:  %s exists but is not a directory\n", cdp);
  210.                         free(cdp);
  211.                         fprintf(stderr, "mapame:  unable to process [%s]\n",
  212.                           filename);
  213.                         return 3;
  214.                     }
  215. #ifdef VMS
  216.                     *xp = '/';  /* for now... (mkdir()) */
  217. #else /* !VMS */
  218. #ifdef MACOS
  219.                     strcat(cdp, ":");
  220. #else /* !MACOS */
  221.                     strcat(cdp, "/");
  222. #endif /* ?MACOS */
  223. #endif /* ?VMS */
  224.                 }
  225.                 pp = name;
  226.                 break;
  227.             case ':':
  228. #ifdef UNIX                       /* colon is a valid character in Unix */
  229.                 *pp++ = workch;   /*  filenames, so keep it; anywhere else, */
  230. #else /* !UNIX */                 /*  change it to an underscore (should  */
  231.                 *pp++ = '_';      /*  NOT have stored drive/node names!!) */
  232. #endif /* ?UNIX */
  233.              /* pp = name;  (OLD) discard DEC dev: or node:: name */
  234.                 break;
  235.             case '.':                   /* DEC-20 generation number
  236.                                          * or MS-DOS type */
  237. #ifdef NUKE_DOTS
  238.                 if (++dc == 1)          /* Keep first dot */
  239.                     *pp++ = workch;
  240. #else /* !NUKE_DOTS */
  241.                 ++dc;                   /* Not used, but what the hell. */
  242.                 *pp++ = workch;
  243. #endif /* ?NUKE_DOTS */
  244.                 break;
  245.             case ';':                   /* VMS generation or DEC-20 attrib */
  246.                 if (V_flag)             /* If requested, save VMS ";##" */
  247.                     *pp++ = workch;     /*  version info; else discard */
  248.                 else                    /*  everything starting with */
  249.                     done = TRUE;        /*  semicolon.  (Worry about */
  250.                 break;                  /*  DEC-20 later.) */
  251.             case '\026':                /* Control-V quote for special chars */
  252.                 quote = TRUE;           /* Set flag for next time. */
  253.                 break;
  254.             case ' ':
  255. #if defined(VMS) || defined(MTS)
  256.                 *pp++ = '_';            /* change spaces to underscore */
  257. #else /* !(VMS || MTS) */               /*  under VMS and MTS, and under DOS */
  258. #ifdef DOS_OS2                          /*  and OS/2 if -s not specified. */
  259.                 if (!sflag)
  260.                     *pp++ = '_';
  261.                 else
  262. #endif /* DOS_OS2 */
  263.                 *pp++ = workch;         /* otherwise, leave as spaces */
  264. #endif /* ?(VMS || MTS) */
  265.                 break;
  266.             default:
  267.                 if (isprint(workch))    /* other printable, just keep */
  268.                     *pp++ = workch;
  269.             }                   /* end switch */
  270.     }                           /* end for loop */
  271.     *pp = '\0';                 /* done with name:  terminate it */
  272.  
  273. /*---------------------------------------------------------------------------
  274.     We COULD check for existing names right now, create a "unique" name, etc.
  275.     At present, we do this in extract_or_test_files() (immediately after we
  276.     return from here).  If conversion went bad, the name'll either be nulled
  277.     out (in which case we'll return non-0), or following procedures won't be
  278.     able to create the extracted file and other error msgs will result.
  279.   ---------------------------------------------------------------------------*/
  280.  
  281.     if (*name == '\0') {
  282.         fprintf(stderr, "mapname:  conversion of [%s] failed\n", filename);
  283.         return 3;
  284.     }
  285.  
  286. #ifdef OS2   /* (if necessary, can use outbuf for temp filename holder) */
  287.     if (longname = !IsFileNameValid(name)) {  /* THIS time, save for file_io */
  288.         last = strrchr(name, '/');
  289.         last = last ? last + 1 : name;  /* should ALWAYS be name... */
  290.         strcpy(longfilename, last);
  291.         fprintf(stderr, "caution:  renaming \"%s\"", name);
  292.         ChangeNameForFAT(last);
  293.         fprintf(stderr, " to \"%s\"\n", name);
  294.     }
  295. #endif /* OS2 */
  296.  
  297.     if (!jflag) {
  298. #ifdef VMS
  299.         *xp++ = ']';            /* proper end-of-dir-name delimiter */
  300.         if (xp == cdp) {        /* no path-name stuff, so... */
  301.             strcpy(filename, name);  /* copy file name into global */
  302.             cdp -= 2;           /*   prepare to free malloc'd space */
  303.         } else {                /* we've added path-name stuff... */
  304.             *xp = '\0';         /*   so terminate... */
  305.             dp = cdp;           /*   and convert to VMS subdir separators:  */
  306.             while (*++dp)       /*   (skip first char:  better not be "/") */
  307.                 if (*dp == '/') /*   change all slashes */
  308.                     *dp = '.';  /*     to dots */
  309.             cdp -= 2;           /*   include leading bracket and dot */
  310.             strcpy(filename, cdp);   /* copy VMS-style path name into global */
  311.             strcat(filename, name);  /* concatenate file name to global */
  312.         }
  313. #else /* !VMS */
  314.         strcpy(filename, cdp);  /* Either "" or slash-terminated path */
  315.         strcat(filename, name); /* append file name to path name */
  316. #endif /* ?VMS */
  317.         free(cdp);
  318.     } else
  319.         strcpy(filename, name); /* copy converted name into global */
  320.  
  321. #if PATH_MAX < (FILNAMSIZ - 1)
  322.     /* check the length of the file name and truncate if necessary */
  323.     if (PATH_MAX < strlen(filename)) {
  324.         fprintf(stderr, "caution:  truncating filename.\n");
  325.         filename[PATH_MAX] = '\0';
  326.         fprintf(stderr, "[ %s ]\n", filename);
  327.         return 1;             /* 1:  warning error */
  328.     }
  329. #endif
  330.  
  331.     return 0;
  332. }
  333.